#include "FileIO_Pkg.h"

std::vector<char> ReadAll(FILE* stream, long offset = 0,
    int origin = SEEK_SET) {
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        return {};
    auto size = ftell(stream) - current;
    std::vector<char> result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        return {};
    fread((void*)result.data(), size, 1, stream);
    return result;
}

std::vector<char> TryReadAll(FILE* stream, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        throw "open file failed";
    auto size = ftell(stream) - current;
    std::vector<char> result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        throw "open file failed";
    fread((void*)result.data(), size, 1, stream);
    return result;
}

std::vector<char> ReadAll(const std::string& file, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    if (!stream) {
        return {};
    }
    return ReadAll(stream, origin);
}

std::vector<char> TryReadAll(const std::string& file, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    if (!stream) {
        throw "open file failed";
    }
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        throw "open file failed";
    auto size = ftell(stream) - current;
    std::vector<char> result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        throw "open file failed";
    fread((void*)result.data(), size, 1, stream);
    return result;
}

std::string ReadAllString(FILE* stream, long offset = 0,
    int origin = SEEK_CUR) {
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        return {};
    auto size = ftell(stream) - current;
    std::string result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        return {};
    fread((void*)result.data(), size, 1, stream);
    return result;
}

std::string TryReadAllString(FILE* stream, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        throw "open file failed";
    auto size = ftell(stream) - current;
    std::string result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        throw "open file failed";
    fread((void*)result.data(), size, 1, stream);
    return result;
}

std::string ReadAllString(const std::string& file, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    if (!stream) {
        return {};
    }
    return ReadAllString(stream, origin);
}

std::string TryReadAllString(const std::string& file, long offset = 0,
    int origin = SEEK_CUR,
    const std::string& mode = "rb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    if (!stream) {
        throw "open file failed";
    }
    auto current = ftell(stream);
    if (fseek(stream, 0, SEEK_END))
        throw "open file failed";
    auto size = ftell(stream) - current;
    std::string result;
    result.resize(size);
    if (fseek(stream, offset, origin))
        throw "open file failed";
    fread((void*)result.data(), size, 1, stream);
    return result;
}

bool WriteAll(FILE* stream, const std::vector<char>& value, long offset = 0,
    int origin = SEEK_CUR) {
    return !fseek(stream, offset, origin) &&
        fwrite(value.data(), value.size(), 1, stream) == 1;
}

bool WriteAll(const std::string& file, const std::vector<char>& value,
    long offset = 0, int origin = SEEK_CUR,
    const std::string& mode = "wb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    return !fseek(stream, offset, origin) &&
        fwrite(value.data(), value.size(), 1, stream) == 1;
}

bool WriteAll(FILE* stream, const std::string& value, long offset = 0,
    int origin = SEEK_CUR) {
    return !fseek(stream, offset, origin) &&
        fwrite(value.data(), value.size(), 1, stream) == 1;
}

bool WriteAll(const std::string& file, const std::string& value,
    long offset = 0, int origin = SEEK_CUR,
    const std::string& mode = "wb") {
    auto stream = fopen(file.c_str(), mode.c_str());
    return !fseek(stream, offset, origin) &&
        fwrite(value.data(), value.size(), 1, stream) == 1;
}